// 列表: 添加行, 删除选中行, 清空行, 排序, 表头表项文本居中, 双击编辑列表项, 显示指定行
package main

import (
	"fmt"
	app "gitee.com/go_888/xcgui/xcgui/app"
	widget "gitee.com/go_888/xcgui/xcgui/widget"
	window "gitee.com/go_888/xcgui/xcgui/window"
	xc "gitee.com/go_888/xcgui/xcgui/xc"
	xcc "gitee.com/go_888/xcgui/xcgui/xcc"
)

var (
	a    *app.X结构_全局API
	w    *window.Window
	list *widget.X结构_列表

	btnAdd   *widget.X结构_按钮
	btnDel   *widget.X结构_按钮
	btnClear *widget.X结构_按钮
	btnJump  *widget.X结构_按钮

	editLine *widget.X结构_编辑框
)

func main() {
	a = app.X创建(true)
	a.X启用DPI(true)
	a.X启用自动DPI(true)
	w = window.X创建窗口(0, 0, 784, 400, "List", 0, xcc.X窗口样式_默认样式)

	// 创建List
	createList()
	// List添加行
	listAddItem()

	var startX int32 = 10
	btnAdd = widget.X创建按钮(startX, 35, 100, 30, "添加20行", w.X句柄)
	btnAdd.X事件_被单击1(onBnClick)

	startX += 100 + 3
	btnDel = widget.X创建按钮(startX, 35, 100, 30, "删除选中行", w.X句柄)
	btnDel.X事件_被单击1(onBnClick)

	startX += 100 + 3
	btnClear = widget.X创建按钮(startX, 35, 100, 30, "删除所有行", w.X句柄)
	btnClear.X事件_被单击1(onBnClick)

	startX += 100 + 3
	btnJump = widget.X创建按钮(startX, 35, 100, 30, "跳转指定行", w.X句柄)
	btnJump.X事件_被单击1(onBnClick)

	startX += 100 + 3
	editLine = widget.X创建编辑框(startX, 35, 100, 30, w.X句柄)

	w.X显示(true)
	a.X运行()
	a.X退出()
}

// 按钮单击事件
func onBnClick(hEle int, pbHandled *bool) int {
	xc.X元素_启用(hEle, false) // 操作前禁用按钮

	switch hEle {
	case btnAdd.X句柄:
		listAddItem()
	case btnDel.X句柄:
		listDelSelectItem()
	case btnClear.X句柄:
		list.X删除行全部()
		list.X重绘(true)
	case btnJump.X句柄:
		row := xc.X文本转整数32位(editLine.X取文本Ex()) - 1
		if row > -1 && row < list.X取项数量AD() {
			list.X显示指定行(row)
			list.X重绘(true)
		}
	}

	xc.X元素_启用(hEle, true) // 操作后解禁按钮
	return 0
}

// 创建List
func createList() {
	// 创建List
	list = widget.X创建列表(10, 70, 764, 315, w.X句柄)
	// 创建表头数据适配器
	list.X创建列表头数据适配器()
	// 创建数据适配器: 5列
	list.X创建数据适配器(5)

	// 列表_置项默认高度和选中时高度
	list.X设置行默认高度(24, 26)
	// 列表_绘制项分割线
	// list.SetDrawRowBkFlags(xcc.List_DrawItemBk_Flag_Line | xcc.List_DrawItemBk_Flag_LineV | xcc.List_DrawItemBk_Flag_Leave | xcc.List_DrawItemBk_Flag_Stay | xcc.List_DrawItemBk_Flag_Select)
	// 表头和表项居中
	listTextAlign()

	// 添加列
	// 如果想要更好看的多功能的List就需要到设计器里设计[列表项模板], 比如说可以在项里添加按钮, 编辑框, 选择框, 组合框等, 可以任意DIY. 可参照例子: List2
	list.X添加列文本(50, "name1", "序号")
	list.X添加列文本(147, "name2", "Column2")
	list.X添加列文本(147, "name3", "Column3")
	list.X添加列文本(147, "name4", "Column4")
	list.X添加列文本(147, "name5", "Column5")

	// 设置序号列可排序, 单击表头时排序
	list.X设置排序(0, 0, true)
	// 这里我使用了置属性的方法是为了不新建多个变量, 因为考虑到组件可能会很多, 当然你也可以用变量来控制.
	// 这个置属性你可以理解为就是给元素绑定的map中赋值. 并不是在操作元素的属性.
	// 也是为了演示Set/GetProperty, 这个东西很有用, 比如说你的列表每1行都有隐藏的值, 就可以存在这里.
	list.X设置属性("sortType", "1") // 1是正序, 0是倒序.
	list.X设置属性("sortFlag", "0") // 只是我设定的标记

	// 列表头项被单击事件
	list.X事件_列表头项点击(func(iItem int32, pbHandled *bool) int {
		// 为了记录排序类型
		if iItem == 0 {
			// 下面这个sortFlag只是我设定的1个标记, 意义是让第1次单击表头排序时不设置sortType的值, 因为第1次默认就是正序
			if list.X取属性("sortFlag") != "1" {
				list.X设置属性("sortFlag", "1")
			} else {
				if list.X取属性("sortType") == "1" {
					list.X设置属性("sortType", "0")
					fmt.Println("列表当前排序: 倒序")
				} else {
					list.X设置属性("sortType", "1")
					fmt.Println("列表当前排序: 正序")
				}
			}
		}
		return 0
	})

	// 列表_鼠标左键双击事件
	list.X事件_左键双击(func(nFlags int, pPt *xc.X结构_坐标, pbHandled *bool) int {
		// 取鼠标点击的行和列
		var row, column int32
		list.X测试点击项EX(pPt, &row, &column)
		fmt.Println("双击行索引:", row, "列索引:", column)
		if row < 0 || column < 0 {
			return 0
		}
		// 取列表行高
		var height int32
		list.X取行高度(row, &height, &height)

		// 创建编辑框
		// 获取双击项的布局元素句柄. 列表默认项都是一个布局元素里放一个形状文本, 布局元素itemID: 0, 形状文本itemID: 1
		// 至于我是怎么知道的, 这个是打开设计器创建一个列表项模板文件后, 就知道它里面是什么了
		hLayout := list.X取项模板对象(row, column, 0)
		if hLayout == 0 {
			return 0
		}
		// 取列宽度
		width := list.X取列宽度(column)
		edit := widget.X创建编辑框(0, 0, width, height, hLayout)
		// 设置编辑框的值为当前列表项内容, 并全选, 置焦点
		text := list.X取项文本(row, column)
		edit.X设置文本(text)
		if text != "" {
			edit.X选择全部()
		}
		w.X设置焦点(edit.X句柄)

		// 存储当前列表项的行和列, 下面要用
		edit.X设置属性("row", xc.X整数32位转文本(row))
		edit.X设置属性("column", xc.X整数32位转文本(column))

		// 编辑框键盘按下事件, 确认修改列表项文本
		edit.X事件_按键按下1(onEleKeyDown)
		// 编辑框失去焦点事件, 销毁编辑框
		edit.X事件_失去焦点1(onEleKillFocus)
		return 0
	})
}

// 元素键盘按下事件
func onEleKeyDown(hEle int, wParam, lParam uintptr, pbHandled *bool) int {
	switch wParam {
	case xcc.X按键_回车: // 回车键
		row := xc.X文本转整数32位(xc.X取属性(hEle, "row"))
		column := xc.X文本转整数32位(xc.X取属性(hEle, "column"))
		list.X设置项文本(row, column, xc.X编辑框_取文本Tmp(hEle))
		xc.X元素_销毁(hEle)
		list.X刷新指定行(row)
		list.X重绘(true)
	case xcc.X按键_Esc: // Esc键
		xc.X元素_销毁(hEle)
		list.X重绘(true)
	}
	return 0
}

func onEleKillFocus(hEle int, pbHandled *bool) int {
	xc.X元素_销毁(hEle)
	list.X重绘(true)
	return 0
}

// 表头和表项居中, 纯代码实现需要记一些api, 需要有清晰的思维, 还是用设计器来的简单, 真要写大程序不可能离开设计器的
func listTextAlign() {
	list.X事件_列表头项模板创建完成(func(pItem *xc.X结构_列表头项, pbHandled *bool) int {
		for i := int32(0); i < list.X取列数量(); i++ {
			hEle := list.X取列表头模板对象(i, 1)
			if a.X句柄是否包含类型(hEle, xcc.X对象句柄类型_形状_文本) { // 是形状文本
				xc.X形状文本_设置文本对齐(hEle, xcc.X文本对齐_水平居中|xcc.X文本对齐_垂直居中)
			}
		}
		return 0
	})

	list.X事件_项模板创建完成(func(pItem *xc.X结构_列表项, nFlag int32, pbHandled *bool) int {
		// nFlag  0:状态改变(复用); 1:新模板实例; 2:旧模板复用
		if nFlag == 1 {
			for i := int32(0); i < list.X取列数量(); i++ {
				hEle := list.X取项模板对象(pItem.Index, i, 1)
				if a.X句柄是否包含类型(hEle, xcc.X对象句柄类型_形状_文本) { // 是形状文本
					xc.X形状文本_设置文本对齐(hEle, xcc.X文本对齐_水平居中|xcc.X文本对齐_垂直居中)
				}
			}
		}
		return 0
	})
}

// List添加20行
func listAddItem() {
	// 循环添加数据
	for i := 0; i < 20; i++ {
		num := list.X取项数量AD() + 1

		// 添加行
		var index int32
		if list.X取属性("sortType") == "1" { // 正序
			index = list.X添加行文本EX("name2", fmt.Sprintf("item%d-Column2", num))
		} else { // 倒序
			index = list.X插入行文本EX(0, "name2", fmt.Sprintf("item%d-Column2", num))
		}
		fmt.Printf("添加行索引: %d\n", index)

		// 置行数据
		// 序号列设置int型的数据才能按数字大小排序
		list.X设置项指数值(index, 0, num)
		list.X设置项文本(index, 2, fmt.Sprintf("item%d-Column3", num))
		list.X设置项文本(index, 3, fmt.Sprintf("item%d-Column4", num))
		list.X设置项文本(index, 4, fmt.Sprintf("item%d-Column5", num))
	}

	list.X重绘(true)
}

// List删除选中行
func listDelSelectItem() {
	count := list.X取选择行数量()
	if count == 0 {
		w.X消息框("提示", "你没有选中列表任何行!", xcc.X消息框_确定按钮|xcc.X消息框_信息图标, xcc.X窗口样式_模态窗口)
		return
	}

	var indexArr []int32
	// 取选中行索引数组
	list.X取全部选择(&indexArr, count)
	// 根据选中行索引数组倒着删, 正着删的话你每删1行下面的行索引就变了
	for i := count - 1; i > -1; i-- {
		list.X删除行(indexArr[i])
		fmt.Printf("删除行索引: %d\n", indexArr[i])
	}

	// 重排剩余行序号
	count = list.X取项数量AD()
	if list.X取属性("sortType") == "1" { // 正序
		for i := int32(0); i < count; i++ {
			list.X设置项指数值(i, 0, i+1)
		}
	} else { // 倒序
		for i, num := int32(0), count; i < count; i, num = i+1, num-1 {
			list.X设置项指数值(i, 0, num)
		}
	}

	// 刷新列表项数据
	list.X刷新项数据()
	// 列表重绘
	list.X重绘(true)
}
